package com.jblog.controller.directive.abs;

import java.util.Map;

import static com.jblog.common.web.FrontUtils.PARAM_PAGE_CSS_CLASS;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.jblog.common.web.FrontUtils;
import com.jblog.common.web.freemarker.DirectiveUtils;
import com.jblog.core.model.account.Account;
import com.jblog.core.model.blog.Category;
import com.jblog.core.model.blog.archive.PostCalendarArchive;
import com.jblog.core.model.blog.order.PostOrder;
import com.jblog.core.model.blog.param.PostParam;
import com.jblog.core.model.common.Privacy;
import com.jblog.core.model.common.Source;
import com.jblog.core.model.common.Status;
import com.jblog.core.service.facde.BlogFacade;

import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;

public abstract class AbstractPostDirective implements
        TemplateDirectiveModel {
    
    protected abstract boolean isPage();
    
    @Autowired protected BlogFacade iblog; 

    public static final String PARAM_CATEGORY_ID       =  "categoryId";
    public static final String PARAM_TAG_IDS           =  "tagIds";
    public static final String PARAM_YEAR              =  "year";
    public static final String PARAM_MONTH             =  "month";
    public static final String PARAM_IS_TOP            =  "isTop";
    public static final String PARAM_SOURCE            =  "source";
    public static final String PARAM_POST_STATUS       =  "postStatus";
    public static final String PARAM_IS_ALLOW_COMMENT  =  "isAllowComment";
    public static final String PARAM_POST_BY           =  "postBy";
    public static final String PARAM_PRIVACY           =  "privacy";
    public static final String PARAM_ORDER_BY              =  "orderBy";
    public static final String PARAM_EXCLUDE_CATEGORY_IDS  =  "excludeCategoryIds";
    public static final String PARAM_TITLE_LEN             =  "titleLen";
    public static final String PARAM_APPEND            =  "append";

    protected Long categoryId(Map<String, TemplateModel> params) throws TemplateException {
        return DirectiveUtils.getLong(PARAM_CATEGORY_ID, params);
    }
    protected String tagIds(Map<String, TemplateModel> params) throws TemplateException {
        return DirectiveUtils.formatString2Ids(DirectiveUtils.getString(PARAM_TAG_IDS, params));
    }
    protected String year(Map<String, TemplateModel> params) throws TemplateException {
        String year = DirectiveUtils.getString(PARAM_YEAR, params);
        return StringUtils.isBlank(year) ? null : year;
    }
    protected String month(Map<String, TemplateModel> params) throws TemplateException {
        String month = DirectiveUtils.getString(PARAM_MONTH, params);
        return StringUtils.isBlank(month) ? null : month;
    }
    protected String excludeCategoryIds(Map<String, TemplateModel> params) throws TemplateException {
        return DirectiveUtils.formatString2Ids(DirectiveUtils.getString(PARAM_EXCLUDE_CATEGORY_IDS, params));
    }
    protected Boolean isTop(Map<String, TemplateModel> params) throws TemplateException {
        return DirectiveUtils.getBool(PARAM_IS_TOP, params);
    }
    protected Source source(Map<String, TemplateModel> params) throws TemplateException {
        String s = DirectiveUtils.getString(PARAM_SOURCE, params);
        return (DirectiveUtils.checkEnum(Source.values(), s)) ? Source.valueOf(s.toUpperCase()) : null;
    }
    protected Status postStatus(Map<String, TemplateModel> params) throws TemplateException {
        String s = DirectiveUtils.getString(PARAM_POST_STATUS, params);
        return (DirectiveUtils.checkEnum(Status.values(), s)) ? Status.valueOf(s.toUpperCase()) : null;
    }
    protected Privacy privacy(Map<String, TemplateModel> params) throws TemplateException {
        String s = DirectiveUtils.getString(PARAM_PRIVACY, params);
        return (DirectiveUtils.checkEnum(Privacy.values(), s)) ? Privacy.valueOf(s.toUpperCase()) : null;
    }
    protected Boolean isAllowComment(Map<String, TemplateModel> params) throws TemplateException {
        return DirectiveUtils.getBool(PARAM_IS_ALLOW_COMMENT, params);
    }
    protected Account postBy(Map<String, TemplateModel> params) throws TemplateException {
        return new Account(DirectiveUtils.getString(PARAM_POST_BY, params));
    }
    protected PostOrder orderBy(Map<String, TemplateModel> params) throws TemplateException {
        String s = DirectiveUtils.getString(PARAM_ORDER_BY, params);
        return (DirectiveUtils.checkEnum(PostOrder.values(), s)) ? PostOrder.valueOf(s.toUpperCase()) : null;
    }
    protected String cssClass(Map<String, TemplateModel> params) throws TemplateException {
        return DirectiveUtils.getString(PARAM_PAGE_CSS_CLASS, params);
    }

    protected Object getData(Map<String, TemplateModel> params, Environment env)
            throws TemplateException {
        
        PostParam postParam;
        if (isPage()) {
            postParam = new PostParam(FrontUtils.start(params, env), FrontUtils.end(params, env));
        } else {
            postParam = new PostParam(FrontUtils.first(params), FrontUtils.count(params));
        }
        postParam.setCategory(new Category(categoryId(params)));
        postParam.setTagIds(tagIds(params));
        postParam.setArchive(new PostCalendarArchive(year(params), month(params)));
        postParam.setExcludeCategoryIds(excludeCategoryIds(params));
        postParam.setIsAllowComment(isAllowComment(params));
        postParam.setIsTop(isTop(params));
        if (null != orderBy(params))
            postParam.setOrder(orderBy(params));
        postParam.setPostBy(postBy(params));
        postParam.setStatus(postStatus(params));
        postParam.setPrivacy(privacy(params));
        postParam.setSource(source(params));
        postParam.setPageNo(FrontUtils.pageNo(env));
        postParam.setPageSize(FrontUtils.count(params));
        postParam.setCssClass(cssClass(params));
        
        if (isPage()) {
            return iblog.findPostByParamByPage(postParam);
        } else {
            return iblog.findPostByParam(postParam);
        }
        
    }
}
